package com.studykun.client.ui;

import java.util.ArrayList;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.InlineLabel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.studykun.client.model.Card;
import com.studykun.client.model.Deck;
import com.studykun.client.model.Syllabus;

public class CardListDialog extends DialogBox {
  final Syllabus syllabus_;
  final FlowPanel clientPanel_ = new FlowPanel();
  final FlowPanel toolPanel_ = new FlowPanel();
  final ArrayList<CheckBox> checkBoxes_ = new ArrayList<CheckBox>();
  
  int lastCheckBoxIndex_ = -1;
  
  public CardListDialog(
      final Syllabus syllabus) {
    syllabus_ = syllabus;
    
    this.setText("Select cards");
    this.setAnimationEnabled(true);
    final Button closeButton = new Button("Close");
    
    final Anchor selectAllAnchor = new Anchor("all");
    selectAllAnchor.addClickHandler(new ClickHandler() {
      public void onClick(ClickEvent event) {
        for (final CheckBox checkBox : checkBoxes_) {
          final boolean previousValue = checkBox.getValue();
          checkBox.setValue(true);
          ValueChangeEvent.fireIfNotEqual(
              checkBox, previousValue, checkBox.getValue());
        }
      }
    });
    
    final Anchor unselectAllAnchor = new Anchor("none");
    unselectAllAnchor.addClickHandler(new ClickHandler() {
      public void onClick(ClickEvent event) {
        for (final CheckBox checkBox : checkBoxes_) {
          final boolean previousValue = checkBox.getValue();
          checkBox.setValue(false);
          ValueChangeEvent.fireIfNotEqual(
              checkBox, previousValue, checkBox.getValue());
        }
      }
    });
    
    toolPanel_.add(new InlineLabel("Select: "));
    toolPanel_.add(selectAllAnchor);
    toolPanel_.add(new InlineLabel(", "));
    toolPanel_.add(unselectAllAnchor);
    
    clientPanel_.setStyleName("cardList");
    toolPanel_.getElement().getStyle().setProperty("textAlign", "left");

    // We can set the id of a widget by accessing its Element
    closeButton.getElement().setId("closeButton");
    VerticalPanel dialogVPanel = new VerticalPanel();
    dialogVPanel.addStyleName("dialogVPanel");
    dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_RIGHT);
    dialogVPanel.add(toolPanel_);
    dialogVPanel.add(clientPanel_);
    dialogVPanel.add(closeButton);
    this.setWidget(dialogVPanel);

    // Add a handler to close the DialogBox
    closeButton.addClickHandler(new ClickHandler() {
      public void onClick(ClickEvent event) {
        CardListDialog.this.hide();
      }
    });
  }
  
  @Override
  public void show() {
    clientPanel_.clear();
    final FlexTable grid = new FlexTable();
    grid.getElement().setClassName("cardGrid");
    
    checkBoxes_.clear();
    
    int rowIndex = 0;
    int i = 0;
    for (final Deck deck : syllabus_.decks()) {
      final InlineLabel deckRowHeading = new InlineLabel(deck.name());
      deckRowHeading.setStylePrimaryName("deckRowHeading");
      grid.setWidget(rowIndex, 0, deckRowHeading);
      grid.getFlexCellFormatter().setColSpan(rowIndex, 0, 2);
      grid.getRowFormatter().getElement(i).setAttribute("row-heading", "true");
      grid.getRowFormatter().setStylePrimaryName(rowIndex, "row");
      if (rowIndex % 2 == 0) {
        grid.getRowFormatter().getElement(i).setAttribute("row-class", "evenRow");
      } else {
        grid.getRowFormatter().getElement(i).setAttribute("row-class", "oddRow");
      }
      ++rowIndex;
      
      for (final Card card : deck.cards()) {
        final int checkBoxIndex = i;
        final CheckBox checkBox = new CheckBox();
        checkBox.setValue(card.selected());
        checkBox.addClickHandler(new ClickHandler() {
          public void onClick(final ClickEvent event) {
            if (event.getNativeEvent().getShiftKey()) {
              final int lastCheckBoxIndex = CardListDialog.this.lastCheckBoxIndex_;
              final int lowerIndex = Math.min(checkBoxIndex, lastCheckBoxIndex);
              final int upperIndex = Math.max(checkBoxIndex, lastCheckBoxIndex);
              
              for (int j = lowerIndex; j < upperIndex + 1; ++j) {
                final CheckBox jCheckBox = CardListDialog.this.checkBoxes_.get(j);
                final boolean previousValue = jCheckBox.getValue();
                jCheckBox.setValue(checkBox.getValue());
                ValueChangeEvent.fireIfNotEqual(
                    jCheckBox, previousValue, jCheckBox.getValue());
              }
            } else {
              CardListDialog.this.lastCheckBoxIndex_ = checkBoxIndex;
            }
          }
        });
        checkBox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
          public void onValueChange(final ValueChangeEvent<Boolean> event) {
            card.selected(checkBox.getValue());
          }
        });
        checkBoxes_.add(checkBox);
        grid.setWidget(rowIndex, 0, checkBox);
        grid.setText(rowIndex, 1, card.kanjiClean());
        grid.getRowFormatter().setStylePrimaryName(rowIndex, "row");
        if (rowIndex % 2 == 0) {
          grid.getRowFormatter().getElement(i).setAttribute("row-class", "evenRow");
        } else {
          grid.getRowFormatter().getElement(i).setAttribute("row-class", "oddRow");
        }
        ++i; ++rowIndex;
      }
    }
    clientPanel_.add(grid);
    super.show();
  }
}
